<?php

/**
 * 处理任务队列的类
 * Class TaskQueueAction
 * @author jie
 * 任务提交成功状态为1, 执行中为2, 执行结束为3, 如果报错,超时等情况,error信息将写入result字段供查询
 */
class TaskQueueAction extends Action
{
    /**
     * 添加任务
     * @param $name /任务名称
     * @param $moduleName /模块名称
     * @param $interfaceName /接口名称
     * @param $param /接口的参数,要求json格式
     * @param $execute_plan_time /执行时间
     * @param $flag /内部调用 true或false
     * @param $isCycleExecute /是否周期执行 0:否, 1:周期
     * @param $cycleTime /周期大小(时间戳)
     * @param $cId /回调时候获取cid
     * @return bool||object
     */
    public function addTaskQueue($name, $moduleName = '', $interfaceName, $param = '', $execute_plan_time = '', $flag=false, $isCycleExecute=0, $cycleTime=0, $cId=0)
    {
        $retVal = Session::init();  //回调时添加任务会导致将失败
        /*if (!$retVal) {
            Output::instance()->resultCode(code_access_denied);
            return;
        }*/
        if($cId){
            $cid = $cId;
        }else{
            $cid = Session::$user['customerId'];
        }
        Session::switchCustomer(0);
        $taskQueue_table = M('task_queue');
        Session::switchCustomer($cid);

        //查询是否同一账号下是否有同个任务正在执行, 存在自媒体可能同一任务没有执行,但再次提交,所以阻止添加取消,后续可以在前端进行判断阻止
        /*$status = $taskQueue_table->where(array('name' => $name, 'cid' => $cid))->getField('status');
        if ($status == 2 || $status == 1) {
            Output::instance()->object(array(
                'code' => -1,
                'msg' => '此任务待执行或正在执行,暂无法创建',
                'data' => ''
            ));
            return;
        }*/
        $data = array();
        $data['name'] = $name;
        $data['cid'] = $cid;
        $data['moduleName'] = $moduleName;
        $data['interfaceName'] = $interfaceName;
        $data['status'] = 1;
        $data['param'] = $param;
        $data['createTime'] = date('Y-m-d H:i:s');
        $data['updateTime'] = date('Y-m-d H:i:s');
        $data['execute_plan_time'] = $execute_plan_time;
        $data['isCycleExecute'] = $isCycleExecute;
        $data['cycleTime'] = $cycleTime;
        /*echo '<br>';
        var_dump($param);
        echo '<br>';exit;*/
        $result = $taskQueue_table->data($data)->filter('strip_tags')->add();
        R('Log/add', array('task', '73', '任务管理', op_add, $taskQueue_table->getLastSql(), '添加一个新的待执行任务'));
        if (!$result) {
            Log::write('jie---taskerror'.$taskQueue_table->getLastSql());
            if($flag){
                return false;
            }

            Output::instance()->resultCode(code_sql_error);
           /*Output::instance()->object(array(
                'code' => -1,
                'msg' => '任务提交失败!',
                'data' => ''
            ));*/
            exit;
        }
        if($flag){
            return true;
        }
        Output::instance()->resultCode(code_success);
        /*Output::instance()->object(array(
            'code' => 0,
            'msg' => '任务提交成功!',
            'data' => ''
        ));*/
        exit;
    }

    /**
     * Linux请求此接口执行任务
     */
    public function executeTask()
    {
        //设置执行时间无限
        if (ini_get('max_execution_time')) {
            ini_set('max_execution_time', '0');
        }
        //一次只能执行一个任务, 判断是否有正在执行的程序
        $taskQueue_table = M('task_queue');
        $result = $taskQueue_table->where(array('status' => 2))->find();
        if ($result) {
            //存在正执行的任务
            exit;
        }
        //查询队列表,执行任务,按照时间1.执行时间没过期 2.执行时间过期
        $map = array();
        $map['status'] = 1;
        $map['execute_plan_time'] = array('ELT', date('Y-m-d H:i:s'));
        $taskInfo = $taskQueue_table->where($map)->find();
        if (!$taskInfo) {
            //没有待执行任务
            exit;
        }
        //设置可以跳过登录
        $_GET['session_id'] = null;
        $_GET['userName'] = null;
        $_GET['uid'] = null;
        $_GET['customerId'] = $taskInfo['cid'];
        //调用接口执行任务
        self::callInterface($taskInfo);
        //执行结束继续调用执行任务
        self::executeTask();
        exit;
    }

    /**
     * 调用接口执行任务
     * @param $taskInfo /任务信息
     */
    public function callInterface($taskInfo)
    {
        //注册程序崩溃后执行的函数
        register_shutdown_function("update_status");
        set_error_handler('my_error_handler', 'E_ERROR');
        //调用接口
        $taskQueue_table = M('task_queue');
        try {
            //将状态改为2执行中
            $updateExecuteStatus = $taskQueue_table
                ->where(array('id' => $taskInfo['id']))
                ->save(array(
                    'status' => 2,
                    'updateTime' => date('Y-m-d H:i:s'),
                    'execute_begin_time' => date('Y-m-d H:i:s')
                ));
            R('Log/add', array('task', '73', '任务管理', op_update, $taskQueue_table->getLastSql(), '开始执行定时任务,任务id为:'.$taskInfo['id']));
            if (!$updateExecuteStatus) {
                Log::write('任务执行失败-----------info111' . $taskInfo['id']);
                throw new Exception('修改任务状态失败');
            }

            $interface = $taskInfo['interfaceName'];
            $relArr = explode('/', $interface);
            $results = new $relArr[0]();
            /*要求调用的接口中,代码出错时抛出异常*/

            $results->$relArr[1]($taskInfo);
        } catch (Exception $e) {
            //不管成功失败,都改变任务状态,避免影响后续任务执行
            Log::write('任务执行失败-----------info222' . $e->getMessage());
        }

        //无论结果如何,将状态改成任务完成
        $updateStatus = $taskQueue_table
            ->where(array('id' => $taskInfo['id']))
            ->save(array(
                'status' => 3,
                'updateTime' => date('Y-m-d H:i:s'),
                'execute_end_time' => date('Y-m-d H:i:s')
            ));
        R('Log/add', array('task', '73', '任务管理', op_update, $taskQueue_table->getLastSql(), '定时任务执行完毕,任务id:'.$taskInfo['id']));
        if (!$updateStatus) {
            Log::write('任务执行失败-----------info333' . $taskQueue_table->getLastSql());
        }
    }
    public function getTaskResult($name){
        $taskQueue_table = M('task_queue');
        $result = $taskQueue_table->where("name='$name'")->field("id,status,result")->order("id desc")->find();
        Output::instance()->object($result);

    }

    /**获取任务记录
     * @param $name /库存同步：synchroStock；订单同步：synchroOrder
     * @param int $start
     * @param int $limit
     */
    public function getSyncRecord($name, $start = 0, $limit = 10)
    {
        $retVal = Session::init();
        if (!$retVal) {
            Output::instance()->resultCode(code_access_denied);
            return;
        }

        $cid = Session::$user["customerId"];
        Session::switchCustomer(0);
        $task_model = M('task_queue');
        Session::switchCustomer($cid);

        $result = $task_model->where(['cid' => $cid, 'name' => $name])->order('createTime desc')->limit($start, $limit)->select();
        foreach ($result as $key => $value) {
            $arrParam = json_decode($value['param'], true);
            $oIds = explode(',', $arrParam['oids']);
            $num = count($oIds);
            $result[$key]['num'] = $num;
        }
        $count = $task_model->where(['cid' => $cid, 'name' => $name])->count();
        if (!$result) $result = [];

        Output::instance()->object([
            'code' => 0,
            'msg' => 'ok',
            'total' => $count,
            'data' => $result
        ]);
    }

    public function getSyncOrder($param)
    {
        $retVal = Session::init();
        if (!$retVal) {
            Output::instance()->resultCode(code_access_denied);
            return;
        }

        $cid = Session::$user["customerId"];
        Session::switchCustomer(0);
        $order_model = M('module_product_order');
        Session::switchCustomer($cid);

        $ids = json_decode($param, true)['oids'];

        R('Product/getProductOrderList', [
            0,
            10000,
            NULL,
            NULL,
            '',
            NULL,
            '',
            '',
            '',
            NULL,
            NULL,
            NULL,
            '',
            '',
            '',
            null,
            NULL,
            NULL,
            0,
            "od.createTime",
            "desc",
            false,
            null,
            null,
            null,
            $ids
        ]);
    }
}

/**
 * 当调用接口出现超时等异常改变任务状态
 */
function update_status(){
    $taskQueue_table = M('task_queue');
    $taskQueue_table
        ->where(array('status' => 2))
        ->save(array(
            'status' => 3,
            'updateTime' => date('Y-m-d H:i:s'),
            'execute_end_time' => date('Y-m-d H:i:s')
        ));
}

/**
 * 当调用接口出现error notice warning是改变状态
 * @param $errno
 * @param $errstr
 * @param $errfile
 * @param $errline
 */
function my_error_handler($errno, $errstr, $errfile, $errline){
    $taskQueue_table = M('task_queue');
    $taskQueue_table
        ->where(array('status' => 2))
        ->save(array(
            'status' => 3,
            'result' => 'ERROR: [ID '.$errno.'] '.$errstr.' (Line: '.$errline.' of '.$errfile.')',
            'updateTime' => date('Y-m-d H:i:s'),
            'execute_end_time' => date('Y-m-d H:i:s')
        ));
}